#! /usr/bin/env python

import sys
import os
import tempfile
import getopt
import subprocess
import shlex
import re
import shutil
if sys.version_info > (3, 0):
	from urllib.request import ProxyHandler, build_opener
	def execfile(filename):
		exec(compile(open(filename).read(), filename, 'exec'))
else:
	from  urllib2 import ProxyHandler, build_opener

TRASHFILE="tag.trash"

GLOBALPARAM={}

def globalparamdef(tmp=""):
	GLOBALPARAM['PATHDEF']=os.path.dirname(os.path.abspath(sys.argv[0]))+os.sep

	GLOBALPARAM['newatomic']=True
	GLOBALPARAM['atomicparsley']="atomicparsley"
	
	GLOBALPARAM['TRASHFILE']=GLOBALPARAM['PATHDEF']+os.sep+TRASHFILE
	if tmp == "":
		GLOBALPARAM['TMP']=tempfile.mkdtemp("autotagshow")+os.sep
	else:
		GLOBALPARAM['TMP']=tmp
	GLOBALPARAM['VERBOSE']=False
	GLOBALPARAM['SRCDIR']=""
	GLOBALPARAM['ID']=""
	GLOBALPARAM['HD']=False
	GLOBALPARAM['cnID']="auto"
	GLOBALPARAM['logcbk']=None

	# read config file
	if os.path.exists(GLOBALPARAM['PATHDEF']+"config.txt"):
		try:
			execfile(GLOBALPARAM['PATHDEF']+"config.txt")
		except:
			print("error parsing config file")
			sys.exit(2)

	if GLOBALPARAM['HTTPPROXY'] != "":	
		GLOBALPARAM['HTTPOPENER']=build_opener(ProxyHandler(GLOBALPARAM['HTTPPROXY']))
	else:
		GLOBALPARAM['HTTPOPENER']=build_opener()

	GLOBALPARAM['trashdict']=loadtrashdict()

def log(str):
	if GLOBALPARAM['logcbk'] != None:
		GLOBALPARAM['logcbk'](str)
	else:
		print(str)

def usage():
	print("""
	autotagshows script 1.0, written by Christophe "KrisT@uF" Genova
	usage
	autotagshows [options] file1 file2 file3 ...
	Options:
	--verbose	verbose mode
	--srcdir	Source dir that contains DB info
	--ID		ID of the show (for one file)
	--HD		To set te HD flag
	--cnID		To set the cnID flag (for SD/HD) (by default it is computed auto)
	""")

def analyzearg(argv):
	try:
		opts, args = getopt.getopt(argv, "", ["verbose","srcdir=","inter","ID=","HD","cnID="])
	except getopt.GetoptError:
		usage()
		sys.exit(2)
	for opt, arg in opts:
		if opt == "--verbose":
			GLOBALPARAM['VERBOSE']=True
		if opt == "--srcdir":
			GLOBALPARAM['SRCDIR']=arg
		if opt == "--ID":
			GLOBALPARAM['ID']=arg
		if opt == "--HD":
			GLOBALPARAM['HD']=True
		if opt == "--cnID":
			GLOBALPARAM['cnID']=arg
	return args

def loadtrashdict():
	dict=[]
	try:
		f=open(GLOBALPARAM['TRASHFILE'],"r")
		for l in f:
			dict.append(" "+l.replace("\n","").upper()+" ")
		f.close()
	except:
		return dict
	return dict

def updatedict(prev, dbname):
	prev=prev.upper().split()
	dbname=dbname.upper().split()

	f=open(GLOBALPARAM['TRASHFILE'],"a")
	log("Updating trash dict")
	if GLOBALPARAM['VERBOSE']:
		log(prev)
		log(dbname)

	for w in prev:
		if not w in dbname:
			log("Adding |"+w+"| to the trash dictionnary")
			f.write(w+"\n")
			
	f.close()


def setfilevar(file):
	fp={}
	fp['path']=file
	fp['dir']=os.path.dirname(os.path.abspath(file))
	fp['name']=os.path.basename(file)
	fp['noext']=os.path.splitext(fp['name'])[0]
	fp['noextclean']=fp['noext'].replace("_for_ipad","").replace("_for_iphone","")
	if GLOBALPARAM['SRCDIR'] == "":
		fp['SRCDIR']=fp['dir']
	else:
		fp['SRCDIR']=GLOBALPARAM['SRCDIR']

	return fp

def cleanfilename(file):
	clean=file
	toclean=[ ".", "+", "_", "-", "]", "[" ]
	for trash in toclean:
		clean=clean.replace(trash," ")

	clean=" "+clean.upper()+" "
	for tag in GLOBALPARAM['trashdict']:
		clean=clean.replace(tag," ")

	clean=clean.replace("  ", " ")	
	clean=clean.replace("  ", " ")	
	clean=clean.replace("  ", " ")	
	clean=clean.replace("  ", " ")	

	if clean[0] == " ":
		clean=clean[1:]
	if len(clean) > 0 and clean[-1] == " ":
		clean=clean[0:-1]
	return clean

def findtag(file):
	meta={ 'showname':"", 'seasonnum':"", 'episodnum':"", 'showtitle':"", 'overview':"", 'released':"", 'serie':False }

	fileparam=setfilevar(file)
	if GLOBALPARAM['VERBOSE']:
		log(fileparam)
	
	fileparam['cleanname']=cleanfilename(fileparam['noextclean'])
	if GLOBALPARAM['VERBOSE']:
		log("Clean name |"+fileparam['cleanname']+"|")

	""" Looking for series season and episod """
	res=re.search("(.*)[ ._-]([0-9][0-9]*)X([0-9][0-9]*)(.*)", fileparam['cleanname'])
	if res == None:
		res=re.search("(.*)[ ._-][sS]([0-9][0-9]*)[eE]([0-9][0-9]*)(.*)", fileparam['cleanname'])
	if res != None:
		meta['serie']=True
		meta['showname']=res.group(1)
		meta['seasonnum']=res.group(2)
		meta['episodnum']=res.group(3)
		meta['showtitle']=res.group(4)
		log("Found serie : |"+meta['showname']+"| Season |"+meta['seasonnum']+"| Episod |"+meta['episodnum']+"| |"+meta['showtitle']+"|")
	else:
		meta['serie']=False
		meta['showname']=fileparam['cleanname']
		log("Cannot find serie info, movie name |"+meta['showname']+"|")

	fileparam['meta']=meta
	return fileparam

def findtagval(tag, data):
	msg=""
	res=re.search(".*<"+tag+">([^\<]*)</"+tag+">.*", data)	
	if res != None:
		tagval=res.group(1)
		log(tag+" = "+tagval)
		if len(res.groups()) > 1:
			log("Warning found several tag!")
	else:
		tagval=""
		log(tag+" = not found")
	return tagval

def getwebfile(url,outfile=""):
	log("Get web file "+url)
	try:
		request = GLOBALPARAM['HTTPOPENER'].open(url)
		content = request.read()
	except:
		return ""

	if outfile != "":
		f=open(outfile, "wb")
		f.write(content)
		f.close()
	return str(content)

def getfile(file):
	if GLOBALPARAM['VERBOSE']:
		log("Reading "+file)
	try:
		with open(file,"r") as f:
			data=f.read()
		if GLOBALPARAM['VERBOSE']:
			log("OK")
	except:
		data=""
		if GLOBALPARAM['VERBOSE']:
			log("KO")
	return data


def getDBdata(fp):
	DB={}
	
	if fp['meta']['serie']:
		# for series, DBInfo is in the dir
		DB['DBFILE']=fp['SRCDIR']+"/DB.Info"
		DB['IDFILE']=fp['SRCDIR']+"/DB.ID"
		DB['IMGFILE']=fp['SRCDIR']+"/DB.jpg"
		DB['EDBFILE']=fp['SRCDIR']+"/"+fp['noextclean']+".DB.Info"
	else:
		# for Movies, DBInfo is in the dir
		DB['DBFILE']=fp['SRCDIR']+"/"+fp['noextclean']+".DB.Info"
		DB['IDFILE']=fp['SRCDIR']+"/"+fp['noextclean']+".DB.ID"
		DB['IMGFILE']=fp['SRCDIR']+"/"+fp['noextclean']+".DB.jpg"
	
	DB['ID']=""
	nbresult=0

	data=getfile(DB['DBFILE'])
	if data != "":
		DB['ID']=findtagval("id", data)
	else:
		if GLOBALPARAM['ID'] != "":
			DB['ID']=GLOBALPARAM['ID']
		else:
			DB['ID']=getfile(DB['IDFILE'])
			if DB['ID'] != "":
				DB['ID']=DB['ID'].replace("\n","")
				nbresults=1
			else:
				#try to find the ID on the web
				url=fp['meta']['showname'].replace(" ","+")
				log("Looking for "+url)
				if fp['meta']['serie']:
					datas=getwebfile("http://www.thetvdb.com/api/GetSeries.php?seriesname="+url+"&language=english", DB['DBFILE'])
					nbresults=datas.count("<Series>")
					log("Nb results "+str(nbresults))
				else:
					datas=getwebfile("http://api.themoviedb.org/2.1/Movie.search/en/xml/356ad15f7c4d16da3ccf2efddf2723e3/"+url, DB['DBFILE'])
					try:
						nbresults=int(findtagval("opensearch:totalResults", datas))
					except:
						nbresults=-1
			if nbresults != 1:
				try:
					os.remove(DB['DBFILE'])
				except:
					print("")	
				log("Cannot find ID")
				return True

			DB['ID']=findtagval("id",datas)


		if DB['ID'] != 0:
			if fp['meta']['serie']:
				data=getwebfile("http://thetvdb.com/api/E4B1E1CFFFF90BF2/series/"+DB['ID'], DB['DBFILE'])
				#data=getwebfile("http://cache.thetvdb.com/data/series/"+DB['ID']+"/", DB['DBFILE'])
			else:
				data=getwebfile("http://api.themoviedb.org/2.1/Movie.getInfo/en/xml/356ad15f7c4d16da3ccf2efddf2723e3/"+DB['ID'], DB['DBFILE'])

	if data != "":
		previousname=fp['meta']['showname']
		if fp['meta']['serie']:
			fp['meta']['showname']=findtagval("SeriesName",data)
			fp['meta']['overview']=findtagval("Overview",data)
			fp['meta']['released']=findtagval("FirstAired",data)
		else:
			fp['meta']['showname']=findtagval("name",data)
			fp['meta']['overview']=findtagval("overview",data)
			fp['meta']['released']=findtagval("released",data)

		updatedict(previousname,fp['meta']['showname'])
			
		if os.path.exists(DB['IMGFILE']) and os.path.getsize(DB['IMGFILE']) == 0:
			os.remove(DB['IMGFILE'])

		if not os.path.exists(DB['IMGFILE']):
			if fp['meta']['serie']:
				imgurl=findtagval("poster", data)
				if imgurl == "":
					imgurl=findtagval("fanart", data)
				imgurl="http://thetvdb.com/banners/"+imgurl
			else:
				imgurl1=re.search(".*<image type=\"poster\" .*url=\"([^\"]*).*size=\"mid\".*", data)
				imgurl2=re.search(".*<image type=\"backdrop\" .*url=\"([^\"]*).*size=\"poster\".*", data)
				imgurl3=re.search(".*<image .*url=\"([^\"]*).*", data)
				imgurl=""
				if imgurl1 != None:
					imgurl=imgurl1.group(1)
				else:
					if imgurl2 != None:
						imgurl=imgurl2.group(1)
					else:
						if imgurl3 != None:
							imgurl=imgurl3.group(1)
			if imgurl != "":
				getwebfile(imgurl, DB['IMGFILE'])
			
		if fp['meta']['serie']:
			# look for episod data
			datae=getfile(DB['EDBFILE'])
			if datae == "":
				ep=int(fp['meta']['episodnum'])
				sea=int(fp['meta']['seasonnum'])
				datae=getwebfile("http://thetvdb.com/api/E4B1E1CFFFF90BF2/series/"+DB['ID']+"/default/"+str(sea)+"/"+str(ep), DB['EDBFILE'])
			if datae != "":
				fp['meta']['showtitle']=findtagval("EpisodeName",datae)
				fp['meta']['descrip']=findtagval("Overview",datae)
				fp['meta']['released']=findtagval("FirstAired",datae)
			else:
				fp['meta']['showtitle']=""
				fp['meta']['descrip']=""
				fp['meta']['released']=""
				
	fp['DB']=DB
	if GLOBALPARAM['VERBOSE']:
		log(fp)
	
	return False

def tagfile(fp):
	cmd=""

	if GLOBALPARAM['cnID'] == "auto":
		tohash=fp['meta']['showname']+fp['meta']['seasonnum']+fp['meta']['episodnum']+fp['meta']['showtitle']
		GLOBALPARAM['cnID']=str(abs(hash(tohash)))
		if GLOBALPARAM['VERBOSE']:
			log("Computing cnID from "+tohash+" = "+GLOBALPARAM['cnID'])

	if fp['meta']['serie']:
		cmd=" --stik \"TV Show\" --TVShowName \""+fp['meta']['showname']+"\" --TVSeasonNum "+fp['meta']['seasonnum']+" --TVEpisodeNum "+fp['meta']['episodnum']+" --TVEpisode \""+fp['meta']['showtitle']+"\" --title \""+fp['meta']['episodnum']+" "+fp['meta']['showtitle']+"\" --description \""+fp['meta']['descrip'][0:254]+"\" --comment \""+fp['meta']['overview'][0:254]+"\" --artwork REMOVE_ALL --year \""+fp['meta']['released']+"\""
		if GLOBALPARAM['newatomic']:
			cmd=cmd+" --longdesc \""+fp['meta']['descrip']+"\""+" --encodedBy \"KrisTouF using iphoneencode\""
	else:
		cmd=" --stik \"Movie\" --title \""+fp['meta']['showname']+"\" --description \""+fp['meta']['overview'][0:254]+"\" --artwork REMOVE_ALL --year \""+fp['meta']['released']+"\""
		if GLOBALPARAM['newatomic']:
			cmd=cmd+" --longdesc \""+fp['meta']['overview']+"\""

	if os.path.exists(fp['DB']['IMGFILE']):
		cmd=cmd+" --artwork \""+fp['DB']['IMGFILE']+"\""

	if GLOBALPARAM['newatomic']:
		if GLOBALPARAM['HD']:
			cmd=cmd+" --hdvideo True"
	
		if GLOBALPARAM['cnID'] != "":
			cmd=cmd+" --cnID "+GLOBALPARAM['cnID']

	cmd="\""+GLOBALPARAM['atomicparsley']+"\" \""+fp['path']+"\""+cmd+" --output \""+GLOBALPARAM['TMP']+"/temptag.m4v\""
	print(cmd)
	if GLOBALPARAM['VERBOSE']:
		log(cmd)
	pipe = subprocess.Popen( shlex.split(cmd))  
	if  pipe.wait() != 0:
		log("Error!!!!!!!!!!!!!!!!!!!!!!")
		if pipe.stderr is not None:
			for l in pipe.stderr:
				log(l)
				log("Command line was "+cmd)
		sys.exit(2)
	shutil.move(GLOBALPARAM['TMP']+"/temptag.m4v",fp['path'])

def autotagfile(file,verbose=False,srcdir="",HD=False,tmp="",ID="",cnID="auto",logcbk=None):
	globalparamdef(tmp)

	GLOBALPARAM['VERBOSE']=verbose
	GLOBALPARAM['SRCDIR']=srcdir
	GLOBALPARAM['ID']=ID
	GLOBALPARAM['HD']=HD
	GLOBALPARAM['cnID']=cnID
	GLOBALPARAM['logcbk']=logcbk

	fileparam=findtag(file)

	if getDBdata(fileparam):
		return True

	tagfile(fileparam)

	return False

def main(argv):
	
	globalparamdef()
	files=analyzearg(argv)
	
	for file in files:
		fileparam=findtag(file)

		if getDBdata(fileparam):
			sys.exit(2)

		tagfile(fileparam)

	if not GLOBALPARAM['VERBOSE']:
		shutil.rmtree(GLOBALPARAM['TMP'])

if __name__ == "__main__":
	main(sys.argv[1:])
